#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<ctype.h>


char cwd[1024];
char enval[1024];
int lastcode = 0;
//#define Debug 1
#define SEP " "
#define NUM 1024
#define SIZE 64

#define NoneRedir   0
#define OutputRedir 1
#define AppendRedir 2
#define InputRedir  3

int redir = NoneRedir;
char *filename = NULL;



const char* getUserName()
{
    char* name = getenv("USER");
    if(name) return name;
    return "none";
}
const char* getHostName()
{
    char* name = getenv("HOSTNAME");
    if(name) return name;
    return "none";
}
const char* getPath()
{
    char* name = getenv("PWD");
    if(name) return name;
    return "none";
}

int getUserCommand(char* command, int num)
{

    printf("[%s@%s %s]#",getUserName(),getHostName(),getPath());
    char* r = fgets(command,num,stdin);
    if(r == NULL) return -1;

    command[strlen(command) - 1] = '\0';
    return strlen(command);
}

void commandSplit(char* in,char* out[])
{ 
    int argc = 0;
    out[argc++] = strtok(in,SEP);
    while(out[argc++] = strtok(NULL,SEP));
#ifdef Debug 
    for(int i = 0;out[i]; i++)
    {
        printf("%d:%s\n",i,out[i]);
    }
#endif
}

int exeCommdand(char* argv[])
{

    pid_t id = fork();
    if(id < 0) return -1;
    else if(id == 0)
    {
        //child
        int fd = 0;
        if(redir == InputRedir)
        {
            fd = open(filename,O_RDONLY);
            dup2(fd,0);
        }
        else if(redir == OutputRedir)
        {
            fd = open(filename,O_CREAT | O_WRONLY | O_TRUNC,0666);
            dup2(fd,1);
        }
        else if(redir == AppendRedir)
        {
            fd = open(filename,O_CREAT | O_WRONLY | O_APPEND,0666); 
            dup2(fd,1);
        }
        else 
        {
            //do nothing
        }
        execvp(argv[0],argv);
        exit(-1);
    }
    else 
    {
        //father 
        int status = 0;
        int n = waitpid(id,&status,0);
        if(n > 0)
        {
            lastcode = WEXITSTATUS(status);
        }        
    }
    return 0;
}

void cd(const char* path)
{
    chdir(path);
    char tem[1024];
    getcwd(tem,sizeof(tem));
    sprintf(cwd,"PWD=%s",tem);
    putenv(cwd);
}
char* homepath()
{
    char* home = getenv("HOME");
    if(home) return home;
    else return (char*)".";

}

int checkBuildCommand(char* argv[])
{
    if(strcmp(argv[0],"cd") == 0)
    {
        char* path = NULL;
        if(argv[1] == NULL) path =homepath();
        else path = argv[1];
        cd(path);
        return 1;
    }
    else if(strcmp(argv[0],"export") == 0)
    {
        strcpy(enval,argv[1]);
        putenv(enval);
        return 1;
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
        if(argv[1] == NULL)
        {
            printf("\n");
            return 1;
        }
        if(*(argv[1])== '$' && strlen(argv[1]) > 1)
        {
            
            char* val = argv[1]+1;//echo $? echo $PATH
            if(strcmp(val,"?") == 0)
            {
                printf("%d\n",lastcode);
                lastcode = 0;
            }
            else 
            {
                printf("%s\n",getenv(val)); 
            }
            return 1;
        }
        else  
        {
            printf("%s\n",argv[1]);
            return 1;
        }
    }
    else if(0){}

    return 0;
}

#define skipSpace(pos) do{ while(isspace(*pos)) ++pos; }while(0)


void checkRedir(char userCommand[],int len)
{
    char *end = userCommand + len - 1;
    char *start = userCommand;
    //ls -a -l > test.txt
    //ls -a -l >> test.txt
    //cat < test.txt
    while(end > start)
    {
        if(*end == '>')
        {
           if(*(end - 1) == '>')
           {
               *(end - 1) = '\0';
               filename = end + 1;
               skipSpace(filename);
               redir = AppendRedir;
               break;
           }
           else  
           {
               *end ='\0';
               filename = end + 1;
               skipSpace(filename);
               redir = OutputRedir;
               break;
           }
        }
        else if(*end == '<')
        {
            *end = '\0';
            filename = end + 1;
            skipSpace(filename);
            redir = InputRedir;
            break;

        }
        else 
        {
            end--;
        }
    }
}

int main()
{
    redir = NoneRedir;
    filename = NULL;
    
    char userCommand[NUM];
    char* argv[SIZE];
    while(1)
    {
      //1.获取命令提示符
      int n = getUserCommand(userCommand,sizeof(userCommand));
      if(n <= 0) continue;
      //1.1检查是否发生了重定向
      checkRedir(userCommand,sizeof(userCommand));
      //2.将获取的命令行参数一个个分开 
      commandSplit(userCommand,argv);
      //3、check and do 内建命令
      n = checkBuildCommand(argv);
      //执行普通命令
      if(n) continue; 
      exeCommdand(argv);
    }

    return 0;
}
